package git.soulbgm.initialize;

import git.soulbgm.config.SysConfig;
import git.soulbgm.service.TableBackupService;
import git.soulbgm.utils.IoUtil;
import git.soulbgm.utils.LogHelper;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 数据库表数据初始化
 *
 * @author SoulBGM
 * @date 2023-01-10
 */
@Component
public class DatabaseTableDataInitialize implements ApplicationRunner {

    /**
     * 初始化数据的根路径
     */
    private static final String INIT_DATA_ROOT_PATH = System.getProperty("user.dir") + File.separator;

    private static final LogHelper LOG = new LogHelper(DatabaseTableDataInitialize.class);

    private final SysConfig config;
    private final TableBackupService tableBackupService;

    public DatabaseTableDataInitialize(SysConfig config, TableBackupService tableBackupService) {
        this.config = config;
        this.tableBackupService = tableBackupService;
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        String initDataPath = config.getInitDataPath();
        String sqlPath = INIT_DATA_ROOT_PATH + initDataPath;
        File file = new File(sqlPath);
        if (!file.exists()) {
            if (config.isTableDataOverwrite()) {
                LOG.error("数据库初始化数据文件不存在");
            }
            return;
        }
        String sql = IoUtil.getFileContent(file);
        if (sql == null) {
            LOG.error("读取数据库初始化数据文件内容失败");
            return;
        }
        sql = formatSql(sql);
        String[] split = sql.split(";\n|;\r\n");
        List<String> tableNames = tableBackupService.getTableNames(sql);
        if (config.isTableDataOverwrite()) {
            delete(split);
        }
        insert(split, tableNames);
    }

    /**
     * 删除
     *
     * @param split SQL数组
     */
    private void delete(String[] split) {
        List<String> execFailSqlList = new ArrayList<>(split.length);
        for (String execSql : split) {
            try {
                tableBackupService.delete(execSql);
            } catch (Exception e) {
                execFailSqlList.add(execSql);
            }
        }

        // 将失败的删除语句进行重试，以防因为外键的原因导致的删除失败
        for (String s : execFailSqlList) {
            tableBackupService.delete(s);
        }
    }

    /**
     * 插入
     *
     * @param split      SQL数组
     * @param tableNames 表名列表
     */
    private void insert(String[] split, List<String> tableNames) {
        int size = tableNames.size();
        List<String> execFailSqlList = new ArrayList<>(size);
        for (int i = 0; i < size; i++) {
            String tableName = tableNames.get(i);
            if (config.isTableDataOverwrite() || tableBackupService.select(tableName, 1, 0).isEmpty()) {
                String execSql = split[i];
                try {
                    tableBackupService.insert(execSql);
                } catch (Exception e) {
                    execFailSqlList.add(execSql);
                }
            }
        }

        // 将失败的插入语句进行重试，以防因为外键的原因导致的插入失败
        for (String s : execFailSqlList) {
            tableBackupService.insert(s);
        }
    }

    /**
     * SQL格式
     *
     * @param sql SQL语句
     * @return {@link String}
     */
    private String formatSql(String sql) {
        StringBuilder builder = new StringBuilder();
        Arrays.stream(sql.split("\n|\r\n"))
                .filter(o -> !o.startsWith("--"))
                .forEach(o -> builder.append(o).append("\n"));
        return builder.toString();
    }

}
